ci: run the test suite and docs build on every push and pull request - #8
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Make GitHub run pyCE's tests automatically on every push and every pull request, so nothing lands untested. Add a GitHub Actions workflow at .github/workflows/tests.yml that: installs the library exactly the way the repository's own published instructions describe (README/getting_started recipe: upgrade pip, then pip install -e '.[test]') rather than installing pytest by hand; runs the test suite with python -m pytest; does this across the FULL range of Python versions the repository claims to support - read from pyproject.toml classifiers and README, which claim 3.10, 3.11, 3.12, 3.13 and 3.14, so the matrix deliberately covers all five rather than a convenient subset; and additionally builds the manual with the docs extra (pip install -e '.[docs]' then make -C docs html) so a broken documentation build is caught too. Deliberate decisions: the workflow is intentionally plain and boring - only actions/checkout and actions/setup-python, no caching, no third-party actions, fail-fast disabled so every matrix entry reports independently. The docs job pins a single Python (3.12) on purpose because the manual build does not need matrixing. Constraint from the user: add ONLY the workflow, plus an instruction fix if the published install recipe turned out to be broken on a clean runner. It was verified locally on clean 3.10 and 3.14 virtualenvs - tests pass and the docs build succeeds - so no instruction fix was needed and no other files are touched. If a claimed Python version genuinely cannot work it must NOT be quietly dropped from the matrix or the test weakened.
What Changed
.github/workflows/tests.yml, which runs on every push and pull request with a read-onlyGITHUB_TOKEN. Atestjob installs via the repository's published recipe (python -m pip install --upgrade pip, thenpip install -e '.[test]') and runspython -m pytestacross Python 3.10-3.14 withfail-fastdisabled; a separatedocsjob pins Python 3.12 and builds the manual withpip install -e '.[docs]'andmake -C docs html. Onlyactions/checkoutandactions/setup-pythonare used - no caching, no third-party actions.docs/Makefileto defaultSPHINXOPTS ?= -W, so Sphinx warnings fail the build. Putting the flag in the Makefile rather than the CI command keeps the README's plainmake -C docs htmlbehaving identically locally and on GitHub, and?=leaves it overridable.docs/conf.pythat drops only intersphinx's "failed to reach any of the inventories" message, so a network blip fetchingobjects.invcannot fail the strict docs build. The Test phase verified this is load-bearing: with the network blocked, the build exits 0 with the filter and fails at the base commit without it, while a genuine broken cross-reference and a malformedintersphinx_mappingstill fail.The Review and Document phases each left one open info note:
-Walone catches structural warnings only (Sphinx nitpicky mode-nwould surface 39 pre-existing docstring type-reference warnings, so it was left out), and the unpinneddocsextra means a future Sphinx release could introduce a new warning that fails the build with no repository change.Risk Assessment
✅ Low: The round-2 change is a two-line hardening of a single CI workflow that applies exactly the requested fixes, touches no library or documentation source, and leaves every intent-required property of the workflow intact.
Testing
Reproduced the workflow's test job locally on real Python 3.10 through 3.14 interpreters using the repository's own published install recipe - all five install cleanly and pass the suite with exit 0, so the full claimed matrix is honest and nothing was quietly dropped. Parsed the workflow YAML as GitHub will read it and asserted every deliberate decision in the intent (triggers, fail-fast disabled, five-version matrix matching the pyproject classifiers, only first-party actions, no caching, docs pinned to 3.12). For this round's docs/conf.py change I confirmed the intersphinx warning's originating logger is exactly the one being filtered, then ran the docs build under six conditions: it exits 0 normally and exits 0 with the inventory unreachable, while the identical blocked-network build against the base-commit conf.py still exits 2 - isolating the fix as the cause. A broken cross-reference, a broken cross-reference combined with an unreachable inventory, and a malformed intersphinx_mapping each still fail the build, proving SPHINXOPTS=-W remains fatal and the suppression is limited to the one network message. The suggested suppress_warnings route was ruled out on evidence: the build output shows that warning carries no subtype tag, unlike the [ref.doc] warning it must keep catching. Captured a full-page screenshot of the rendered manual so the docs job is shown producing a correct product rather than just a zero exit code. Transient venvs, build output, and caches were removed; the worktree is clean. No actionable issues.
/var/folders/ym/vnmfjh5n7dn2vdzdgy7zrbjh0000gn/T/no-mistakes-evidence/01M0CBYV59RKEHCGCZCCE5M03Y/docs-manual-index.png)Evidence: Docs build behaviour across all six scenarios (the core evidence for this round's fix)
### docs job:make -C docs html SPHINXOPTS=-Wunder Sphinx 9.1.0 / Python 3.12 scenario conf.py exit outcome -------------------------------------------------- --------- ---- -------------------------------- A network available, docs unchanged HEAD 0 build succeeded B intersphinx inventory UNREACHABLE HEAD 0 build succeeded, warning dropped B' intersphinx inventory UNREACHABLE 6f1b073 2 make: *** [html] Error 1 (base commit, i.e. WITHOUT the fix) "1 warning (treated as errors)" C broken cross-reference :doc:no_such_pageHEAD 2 make: *** [html] Error 1 network available "unknown document [ref.doc]" D broken cross-reference AND inventory unreachable HEAD 2 make: *** [html] Error 1 only the intersphinx msg dropped E malformed intersphinx_mapping value HEAD 2 ConfigError, hard failure A vs B -> an unreachable inventory no longer fails the build. B vs B' -> the docs/conf.py filter is what changed that; nothing else. C, D, E -> warnings are still fatal; the suppression is limited to one message.Evidence: Before/after on the same blocked network: base commit fails, HEAD succeeds
### WITHOUT the fix (docs/conf.py from base commit 6f1b073), inventory unreachable: $ make -C docs html SPHINXOPTS=-W WARNING: failed to reach any of the inventories with the following issues: intersphinx inventory 'https://docs.python.org/3/objects.inv' not fetchable due to ProxyError build finished with problems, 1 warning (with warnings treated as errors). make: *** [html] Error 1 exit=2 ### WITH the fix (HEAD), identical blocked network: $ make -C docs html SPHINXOPTS=-W loading intersphinx inventory 'python' from https://docs.python.org/3/objects.inv ... build succeeded. The HTML pages are in _build/html. exit=0Evidence: Genuine warnings still fail the build under -W
### Broken cross-reference :doc:no_such_pageinjected into docs/index.rst $ make -C docs html SPHINXOPTS=-W docs/index.rst:118: WARNING: unknown document: 'no_such_page' [ref.doc] build finished with problems, 1 warning (with warnings treated as errors). make: *** [html] Error 1 exit=2 ### Note: this warning carries the [ref.doc] subtype, while the intersphinx one ### carries none - which is why suppress_warnings cannot target it.Evidence: Full CI matrix: test suite on every claimed Python version
###pip install -e '.[test]'thenpython -m pytestin a clean venv per version python 3.10 | 5 passed | exit=0 python 3.11 | 5 passed | exit=0 python 3.12 | 5 passed | exit=0 python 3.13 | 5 passed | exit=0 python 3.14 | 5 passed | exit=0Evidence: Workflow structure as GitHub will read it, checked against the stated intent
triggers : ['pull_request', 'push'] permissions : {'contents': 'read'} jobs : ['test', 'docs'] [test job] fail-fast : False python matrix : ['3.10', '3.11', '3.12', '3.13', '3.14'] step: Install pyCE with the test extra $ python -m pip install --upgrade pip $ pip install -e '.[test]' step: Run the test suite $ python -m pytest [docs job] pinned python : 3.12 step: Install pyCE with the docs extra $ pip install -e '.[docs]' step: Build the manual $ make -C docs html SPHINXOPTS=-W actions used : ['actions/checkout', 'actions/setup-python'] third-party actions : none cache usage : none classifiers claim : ['3.10', '3.11', '3.12', '3.13', '3.14'] matrix covers : ['3.10', '3.11', '3.12', '3.13', '3.14'] MATRIX == CLAIMS : TrueEvidence: Full transcript of the CI test matrix reproduction (installs + pytest output per version)
Evidence: Filter narrowness check: unreachable inventory does not mask a real warning
Evidence: Malformed intersphinx_mapping still hard-fails the build
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
.github/workflows/tests.yml:7- The workflow declares nopermissions:block, so both jobs inherit the repository's default GITHUB_TOKEN scope, which on older repos is contents:write. Neither job uses the token for anything butactions/checkout, andpip install -e '.[test]'executes arbitrary build code from the dependency tree (numpy/scipy/matplotlib/astropy and their sdists) on every push to a branch in the repo. Adding a top-levelpermissions:\n contents: readabovejobs:drops the token to read-only for both jobs with no behavioral change; it is neither caching nor a third-party action, so it does not conflict with the "plain and boring" constraint..github/workflows/tests.yml:38-make -C docs htmluses the Makefile's emptySPHINXOPTS(docs/Makefile:6), so sphinx-build exits 0 on warnings and only hard errors fail the job. The most likely real docs regression in this repo - an autodoc import failure in one of thedocs/apipages, or a broken cross-reference - is emitted as a warning, so the page renders empty and CI still reports green.make -C docs html SPHINXOPTS=-Wwould make the job actually catch that, but it deviates from the published README recipe and may surface pre-existing warnings, so it is the author's call rather than a mechanical fix..github/workflows/tests.yml:4- Becausepushandpull_requestare both unfiltered, every commit on a same-repo PR branch triggers two full runs (10 test jobs + 2 docs jobs), and with noconcurrency:group superseded runs are not cancelled. This is the direct consequence of the explicitly required "every push and every pull request" behavior and is noted as a cost/noise tradeoff only, not a defect.🔧 Fix: Restrict workflow token scope and fail docs build on warnings
1 info still open:
.github/workflows/tests.yml:41--Wnow escalates every Sphinx warning to a build failure, including two that depend on the runner environment rather than on the change under test: (a)docs/conf.py:199setsintersphinx_mapping = {'python': ('https://docs.python.org/3', None)}, so each build fetches objects.inv over the network and a transient fetch failure emits "failed to reach any of the inventories", which is now a red docs job; (b) the docs extra is unpinned (pyproject.toml:34-38lists baresphinx,sphinx_rtd_theme,sphinx-copybutton), so the job resolves the newest Sphinx on every run and any newly-introduced warning from an upstream release fails the build with no repository change. This is the accepted cost of the explicitly requested fail-on-warnings behavior, and neither mitigation (anintersphinx_timeout/suppress_warningssetting, or pinning the docs extra) is reachable without editing files the instructions place off-limits for this change, so it is noted only as a follow-up location if the docs job starts flaking.🔧 **Test** - 1 issue found → auto-fixed ✅
.github/workflows/tests.yml:41- The docs job fetches the intersphinx inventory from https://docs.python.org/3/objects.inv on every run, and the review commit'sSPHINXOPTS=-Wmakes that network dependency fatal. I reproduced it: with the inventory unreachable, Sphinx emitsWARNING: failed to reach any of the inventories, and under -W the build ends withbuild finished with problems, 1 warning (with warnings treated as errors)andmake: *** [html] Error 1. A transient outage or network blip on the runner therefore turns the docs job red for reasons unrelated to the change being tested. This is not failing today (the docs job passes with -W when the network is up), and the remedy is a product decision rather than a test fix - either drop -W, or keep it and make intersphinx resolution non-fatal - so I left the workflow untouched for you to decide.git archive c9fee24 | tar -xinto 6 clean throwaway trees, one per CI job, outside the worktreepython3.10 -m venv+python -m pip install --upgrade pip+pip install -e '.[test]'+python -m pytest(5 passed)python3.11 -m venv+python -m pip install --upgrade pip+pip install -e '.[test]'+python -m pytest(5 passed)python3.12 -m venv+python -m pip install --upgrade pip+pip install -e '.[test]'+python -m pytest(5 passed)python3.13 -m venv+python -m pip install --upgrade pip+pip install -e '.[test]'+python -m pytest(5 passed)python3.14 -m venv+python -m pip install --upgrade pip+pip install -e '.[test]'+python -m pytest(5 passed)docs job on 3.12:pip install -e '.[docs]'thenmake -C docs html SPHINXOPTS=-W(build succeeded)Negative control: reintroduced the historicalalpha_rangemutation bug in a throwaway copy, confirmedpython -m pytestexits 1 andtest_callers_list_untouchedfailsFlake probe: reranmake -C docs html SPHINXOPTS=-Wwith intersphinx unreachable (proxy blackhole) to check warnings-as-errors behaviourStructural validation of.github/workflows/tests.ymlparsed with PyYAML, diffed matrix againstpyproject.tomlclassifiers viatomllibCompared the workflow install steps against the published recipe indocs/getting_started.rstandREADME.mdVisual capture of the manual produced by the docs job viachrome-devtools-axi screenshot --full-pageon index, getting_started and api/pyCE.math pages🔧 Fix: Stop unreachable intersphinx inventory failing docs build
✅ Re-checked - no issues remain.
python3.{10,11,12,13,14} -m venv+python -m pip install --upgrade pip+pip install -e '.[test]'+python -m pytest- full CI matrix reproduced on real interpreters, 5 passed / exit 0 on all five versionspython -m pytest -qre-run per venv capturing explicit exit codes (all exit=0)YAML parse of.github/workflows/tests.ymlasserting triggers,fail-fast: false, matrix contents, step commands, actions used, absence of caching, and matrix == pyproject Python classifierspip install -e '.[docs]'thenmake -C docs html SPHINXOPTS=-Won Python 3.12 / Sphinx 9.1.0 - scenario A, network available, exit 0https_proxy=http://127.0.0.1:9 make -C docs html SPHINXOPTS=-W- scenario B, intersphinx inventory unreachable, exit 0, warning droppedSame blocked-network build withdocs/conf.pyrestored from base commit6f1b073- scenario B-baseline, exit 2,make: *** [html] Error 1(proves the fix is load-bearing)make -C docs html SPHINXOPTS=-Wwith a genuine broken cross-reference:doc:no_such_page`` injected into docs/index.rst - scenario C, exit 2 onunknown document [ref.doc]Broken cross-reference AND unreachable inventory together - scenario D, exit 2, confirming only the single intersphinx message is filteredmake -C docs html SPHINXOPTS=-Wwith a deliberately malformedintersphinx_mappingvalue - scenario E, exit 2 with ConfigErrorIntrospection ofsphinx.ext.intersphinx._shared.LOGGER.logger.nameconfirming it equalssphinx.sphinx.ext.intersphinx, the logger docs/conf.py attaches its filter tochrome-devtools-axi open file://.../docs/_build/html/index.html+screenshot --full-page- visual confirmation the docs job's output renders correctlygit status --porcelain/git diff --statafter cleanup - worktree clean, only .github/workflows/tests.yml and docs/conf.py differ from the base commitREADME.md:56- README's local docs recipe ismake -C docs html, while the new CI docs job builds withSPHINXOPTS=-W, so a contributor can build the manual cleanly on their machine and still have CI fail on a Sphinx warning. I did not change README because the author's intent explicitly constrains this change to the workflow file alone (plus an install-instruction fix, which was not needed). Worth a follow-up decision: either documentmake -C docs html SPHINXOPTS=-Win the README Documentation section, or defaultSPHINXOPTS = -Windocs/Makefileso local and CI builds agree without duplicating the flag in prose.🔧 Fix: Default docs Makefile to -W, drop CI's duplicate flag
1 info still open:
docs/Makefile:5- The strict build now agreed between README and CI, but -W alone is narrower than it sounds: Sphinx's nitpicky mode is off by default, so an unresolved Python cross-reference such as :py:func:pyCE.math.does_not_existproduces no warning and the build still exits 0. I verified this directly - only structural warnings (stale toctree entry, malformed directive, duplicate label) fail. Closing that gap means adding -n, which is out of scope here because it is not mechanical: a measuredmake -C docs html SPHINXOPTS=-nrun emits 39 pre-existing warnings, overwhelminglypy:class reference target not foundfor docstring type names that are not real classes (18xndarray, plusshape,len,N,x,3,phi,denFT). Enabling -n today would turn a green docs job red. Follow-up decision for you: either leave -W as-is (structural correctness only, which is what the Makefile comment now states), or do a separate docstring pass - normalizendarraytonumpy.ndarrayso intersphinx resolves it, move non-type annotations out of type position, and add a smallnitpick_ignorein docs/conf.py for the genuine leftovers - and only then add -n to the default SPHINXOPTS.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.